package com.yanxibao.util;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 敏感词替换
 *
 * @author kongke
 */
public class SensWord {


    /**
     * 敏感词替换
     *
     * @param oldStr    原话
     * @param sensWords 敏感词列表
     * @param sensMap   敏感词键值对(包含敏感词与对应替换词)
     * @param skip      跳过字符
     * @return 替换之后
     */
    public String replaceTo(String oldStr, List<String> sensWords, Map<String, String> sensMap, char[] skip) {
        String newStr = oldStr;
        char[] str = newStr.toCharArray();
        for (int i = 0; i < str.length; i++) {
            boolean isExit = false;
            int[] indexes = new int[5];
            int index = 0;
            char c = str[i];
//            在敏感词列表中查询相关字符
            List<String> matchWord = selectWord(c, sensWords, index);
            while (!matchWord.isEmpty()) {

//                判断敏感词长度
                int wordLen = matchWord.get(0).length();
//                对长短敏感词的不同处理
                if (wordLen == 1) {
//                    直接用newStr替换是为了替换不同长度的敏感词
                    newStr = newStr.replaceFirst(String.valueOf(str[i]), sensMap.get(matchWord.get(0)));
//                    每一次替换都将str和i更新
                    str = newStr.toCharArray();
                    i += (sensMap.get(matchWord.get(0)).length() - 1);
                    break;
                } else if (wordLen > 1) {
//                    将长敏感词在字符串中下标暂时存贮
                    if (!isExit) {
                        indexes[index] = i;
                    }

//                    检查到敏感词的最后一位则开始替换
                    if (index == wordLen - 1) {
                        char[] sWord = sensMap.get(matchWord.get(0)).toCharArray();
                        for (int j = 0; j < wordLen; j++) {
                            str[indexes[j]] = sWord[j];
                        }
//                        每一次替换都将newStr更新
                        newStr = String.valueOf(str);
                        break;
                    }
                    i++;
                    char nextChar = str[i];
//                  如果有符号之类的字符则忽略
                    isExit = isExist(skip, nextChar);
                    if (isExit) {
                        continue;
                    }
                    index++;
                    matchWord = selectWord(nextChar, matchWord, index);

                } else {
                    return " 数据错误! ---> 检查 CanTalk.selectWord.related ";
                }
            }
        }
        return newStr;
    }

    /**
     * 在数组中查找相关词组
     *
     * @param c         目标字符
     * @param sensWords 敏感词集
     * @return {@link List}
     */
    private List<String> selectWord(char c, List<String> sensWords, int index) {
        List<String> related = new ArrayList<>();
        for (String word : sensWords) {
            char[] w = word.toCharArray();
//            包含相同字符则为有关联，index为标记第几次比较
            if (c == w[index]) {
                related.add(word);
            }
        }
        return related;
    }

    /**
     * 判断是否存在特殊字符
     *
     * @param skip 特殊字符集
     * @param c    可疑字符
     * @return boolean
     */
    private boolean isExist(char[] skip, char c) {
        for (char sc : skip) {
            if (c == sc || c == ' ') {
                return true;
            }
        }
        return false;
    }
}
